#include <QGLWidget>
#include <algorithm>

#include "matrixstack.h"
#include "myglwidget.h"
#include "mainwindow.h"

MatrixStack::MatrixStack(MyGLWidget &glWidget, MainWindow &mainWindow)
: m_glWidget(glWidget),
  m_mainWindow(mainWindow)
{
	m_resultMtx.identity();
}

void MatrixStack::applyStack()
{
	glPushMatrix();
	glMultMatrixf(m_resultMtx.data());
}

void MatrixStack::popStack()
{
	glPopMatrix();
}


int MatrixStack::pushMatrix(const Matrix &mtx)
{
	MatrixRecord mtr(m_list.size(), mtx);
	m_list.push_back(mtr);
	
	m_resultMtx *= mtr.mtx;

	m_glWidget.updateGL();

	return mtr.id;
}

int MatrixStack::pushMatrix()
{
	MatrixRecord mtr(m_list.size());

	m_list.push_back(mtr);

	return mtr.id;
}

void MatrixStack::updateResultMtx()
{
	m_resultMtx.identity();

	for ( MatrixList::const_iterator i = m_list.begin(); i != m_list.end(); ++i )
	{
		m_resultMtx *= i->mtx;
	}

	m_glWidget.updateGL();
}

bool MatrixStack::moveMatrixUp(int id)
{
	MatrixList::iterator item = findMatrix(id);

	if ( item == m_list.end() || item == m_list.begin() )
	{
		return false;
	}

	MatrixList::iterator prev = item;
	--prev;

	std::swap(*item, *prev);
	updateResultMtx();

	m_mainWindow.matrixMovedUp(id);

	return true;
}

bool MatrixStack::moveMatrixDown(int id)
{
	MatrixList::iterator item = findMatrix(id);

	if ( item == m_list.end() )
	{
		return false;
	}

	MatrixList::iterator next = item;
	++next;

	if ( next == m_list.end() )
	{
		return false;
	}

	std::swap(*item, *next);
	updateResultMtx();

	m_mainWindow.matrixMovedDown(id);

	return true;
}

MatrixStack::MatrixList::iterator MatrixStack::findMatrix(int id)
{
	for ( MatrixList::iterator i = m_list.begin(); i != m_list.end(); ++i )
	{
		if ( i->id == id )
		{
			return i;
		}
	}

	return m_list.end();
}

Matrix &MatrixStack::getMatrix(int id)
{
	return findMatrix(id)->mtx;
}

